package com.cloudpark.common.util.wechat;

import java.io.UnsupportedEncodingException;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Formatter;
import java.util.HashMap;
import java.util.Map;

import org.apache.commons.lang3.StringUtils;
import org.apache.log4j.Logger;
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.DocumentHelper;
import org.dom4j.Element;

import com.alibaba.fastjson.JSON;
import com.cloudpark.common.util.CommonUtil;
import com.cloudpark.common.util.Constants;
import com.cloudpark.common.util.HttpRequestUtil;
import com.cloudpark.common.util.MessageUtil;
import com.cloudpark.common.util.ObjectUtil;
import com.cloudpark.common.util.wechat.WxManagerUtil;

public class WeChatPayUtil {

	private static final Logger log = Logger.getLogger(WeChatPayUtil.class);

	/**
	 * 微信支付请求入口
	 * @param appId
	 * @param appSecret
	 * @param keySecret
	 * @param mch_id
	 * @param openId
	 * @param total_fee
	 * @param spbill_create_ip
	 * @param body
	 * @param out_trade_no
	 * @param attach
	 * @param notify_url
	 * @param dynamicURL
	 * @return
	 */
	public static String initWeixinPay(String appId, String appSecret,
			String keySecret, String mch_id, String openId, String total_fee,
			String spbill_create_ip, String body, String out_trade_no,
			String attach, String notify_url, String dynamicURL) {
		String result = "";
		try {
			String nonce_str = CommonUtil.getRandomString(30);
			String timestamp = create_timestamp();
			String jsapi_ticket = WxManagerUtil.getTicket(appId, appSecret);
			String signature = getShaSign(jsapi_ticket, nonce_str, timestamp, dynamicURL);

			if (ObjectUtil.isBlank(signature)) {
				result = MessageUtil.error("SHA签名错误");
				return result;
			}
			log.info("nonceStr=========" + nonce_str);
			log.info("timestamp=========" + timestamp);
			log.info("signature=========" + signature);
			log.info("appId=========" + appId);
			log.info("url=========" + dynamicURL);
			log.info("jsapi_ticket=========" + jsapi_ticket);

			Map<String, Object> dataMap = new HashMap<String, Object>();
			dataMap.put("appId", appId);
			dataMap.put("signature", signature);
			dataMap.put("timestamp", timestamp);
			dataMap.put("nonceStr", nonce_str);

			// 向微信服务端下单
			Map<String, Object> orderSign = getUnifiedOrder(nonce_str,
					timestamp, appId, appSecret, keySecret, mch_id, openId,
					total_fee, spbill_create_ip, body, out_trade_no, attach,
					notify_url);
			dataMap.put("WxOrder", orderSign);

			Map<String, Object> map = new HashMap<String, Object>();
			map.put("data", dataMap);
			map.put("code", Constants.OK);
			result = JSON.toJSONString(map);
		} catch (Exception e) {
			e.printStackTrace();
		}
		return result;
	}

	/**
	 * 统一下单
	 * 
	 * @param nonce_str
	 * @param timestamp
	 * @param appId
	 * @param appSecret
	 * @param keySecret
	 * @param mch_id
	 * @param openId
	 * @param total_fee
	 * @param spbill_create_ip
	 * @param body
	 * @param out_trade_no
	 * @param attach
	 * @param notify_url
	 * @return
	 */
	private static Map<String, Object> getUnifiedOrder(String nonce_str,
			String timestamp, String appId, String appSecret, String keySecret,
			String mch_id, String openId, String total_fee,
			String spbill_create_ip, String body, String out_trade_no,
			String attach, String notify_url) {

		String prepay_id = "prepay_id=";
		String trade_type = "JSAPI";
		String sign = "";
		String requestUrl = WxManagerUtil.getWxPayUnif();

		Map<String, String> map = new HashMap<String, String>();
		map.put("body", body);
		map.put("out_trade_no", out_trade_no);
		map.put("spbill_create_ip", spbill_create_ip);
		map.put("appid", appId); // 验证里面没有驼峰标识,有点反人类，注意就好
		map.put("mch_id", mch_id);
		map.put("nonce_str", nonce_str);
		map.put("trade_type", trade_type);
		map.put("notify_url", notify_url);
		map.put("openid", openId); // 验证里面没有驼峰标识,有点反人类，注意就好
		map.put("attach", attach);

		if (null != total_fee && !total_fee.isEmpty()) {
			if (total_fee.indexOf(".") > -1) {
				String znum = total_fee.substring(0, total_fee.indexOf("."));
				String lnum = total_fee.substring(total_fee.indexOf(".") + 1);
				Integer totalMoney = 0;
				if (znum.length() >= 1) {
					totalMoney = Integer.valueOf(znum) * 100;
				}
				if (lnum.length() == 1) {
					String J = lnum.substring(0, 1);
					totalMoney = totalMoney + Integer.valueOf(J) * 10;
				} else if (lnum.length() > 1) {
					String J = lnum.substring(0, 1);
					String F = lnum.substring(1, 2);
					totalMoney = totalMoney + Integer.valueOf(J) * 10
							+ Integer.valueOf(F);
				}
				map.put("total_fee", String.valueOf(totalMoney));
			} else {
				map.put("total_fee", total_fee + "00");// 单位：分
			}
			log.info("######金额转换正常######");
		} else {
			log.error("######金额为空######");
		}

		sign = CommonUtil.getWxSign(map, keySecret);
		map.put("sign", sign);

		String param = CommonUtil.maptoxmlNohead(map);
		String msg = HttpRequestUtil.sendPost(requestUrl, param);

		if (StringUtils.isNoneEmpty(msg)) {
			try {
				Document document = DocumentHelper.parseText(msg);
				Element root = document.getRootElement();
				String return_code = root.element("return_code").getText();
				String return_msg = root.element("return_msg").getText();
				if (return_code.equals("SUCCESS") || return_code.indexOf("SUCESS") > -1) {
					String result_code = root.element("result_code").getText();
					if (result_code.equals("SUCCESS") || return_code.indexOf("SUCESS") > -1) {
						prepay_id = prepay_id + root.element("prepay_id").getText();
						log.info("生成支付订单-->成功" + prepay_id);
					} else {
						log.error("######调用微信生成支付订单接口失败 ，"
								+ root.element("err_code_des").getText());
					}
				} else {
					log.error("######调用微信生成支付订单接口失败 ，" + return_msg);
				}
			} catch (DocumentException e) {
				e.printStackTrace();
			}
		} else {
			log.info("######调用微信生成支付订单接口失败 ");
		}

		/**
		 * 生成签名
		 */
		Map<String, String> mapSign = new HashMap<String, String>();
		mapSign.put("appId", appId);
		mapSign.put("timeStamp", timestamp);
		mapSign.put("nonceStr", nonce_str);
		mapSign.put("package", prepay_id);
		mapSign.put("signType", "MD5");
		String paySign = CommonUtil.getWxSign(mapSign, keySecret);

		/**
		 * 返回授权信息
		 */
		Map<String, Object> dataMap = new HashMap<String, Object>();
		dataMap.put("timestamp", timestamp);
		dataMap.put("nonceStr", nonce_str);
		dataMap.put("prepay_id", prepay_id);
		dataMap.put("signType", "MD5");
		dataMap.put("paySign", paySign);
		dataMap.put("orderNo", out_trade_no);
		return dataMap;
	}

	private static String getShaSign(String jsapi_ticket, String nonce_str,
			String timestamp, String dynamicURL) {
		// 注意这里参数名必须全部小写，且必须有序
		String signature = "";
		String stringParams = "jsapi_ticket=" + jsapi_ticket + "&noncestr="
				+ nonce_str + "&timestamp=" + timestamp + "&url=" + dynamicURL;
		log.info("stringParams=========" + stringParams);
		try {
			MessageDigest crypt = MessageDigest.getInstance("SHA-1");
			crypt.reset();
			crypt.update(stringParams.getBytes("UTF-8"));
			signature = byteToHex(crypt.digest());
		} catch (NoSuchAlgorithmException e) {
			log.error("SHA-1签名错误", e);
		} catch (UnsupportedEncodingException e) {
			log.error("SHA-1签名错误", e);
		}
		return signature;
	}

	private static String byteToHex(final byte[] hash) {
		Formatter formatter = new Formatter();
		for (byte b : hash) {
			formatter.format("%02x", b);
		}
		String result = formatter.toString();
		formatter.close();
		return result;
	}

	private static String create_timestamp() {
		return Long.toString(System.currentTimeMillis() / 1000);
	}
}
